﻿using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Net;
using LitJson;
using System.Threading;

class ServerManager
{
    private static ServerManager _instance;
    public static ServerManager Instance()
    {
        if (_instance == null)
        {
            _instance = new ServerManager();
        }
        return _instance;
    }

    Dictionary<string, SocketClient> dic = new Dictionary<string, SocketClient>();
    TcpListener listener;
    string IP = "192.168.11.18";
    int Port = 8500;

    int HeartInterval = 5 * 1000;
    private ServerManager()
    {
        IPAddress address = IPAddress.Parse(IP);
        listener = new TcpListener(address, Port);
        //绑定ip和port，进行侦听
        listener.Start();
        Console.WriteLine("开始侦听");

        //异步监听客户端连接
        listener.BeginAcceptTcpClient(OnAccecpt, null);

        Timer timer = new Timer(CallBack,null,HeartInterval,HeartInterval);
    }

    void CallBack(object state)
    {
        BroadAll(Protocol.HeartBeat);
    }

    //客户端连接成功
    void OnAccecpt(IAsyncResult result)
    {
        //获取连接的客户端
        TcpClient client = listener.EndAcceptTcpClient(result);
        //封装到SocketClient里面，进行通信
        SocketClient remote = new SocketClient(client);

        //再次开启监听
        lock (listener)
        {
            listener.BeginAcceptTcpClient(OnAccecpt, null);
        }
    }


    //广播所有人消息<包含自己>
    public void BroadAll(int protocal, string msg)
    {
        foreach (KeyValuePair<string, SocketClient> item in dic)
        {
            item.Value.SendMessage(protocal, msg);
        }
    }
    public void BroadAll(int protocal)
    {
        foreach (KeyValuePair<string, SocketClient> item in dic)
        {
            item.Value.SendMessage(protocal);
        }
    }

    //广播给其他人
    public void BroadOther(SocketClient client, int protocal, string msg)
    {
        foreach (KeyValuePair<string, SocketClient> item in dic)
        {
            if (item.Key != client.GetIpPort())
            {
                item.Value.SendMessage(protocal, msg);
            }
        }
    }

    //把断开的客户端，移除掉
    public void RemoveClient(SocketClient client)
    {
        //连接socket但未登陆的用户不用移除
        if (client.userdata != null)
        {
            string username = client.userdata.username;

            Console.WriteLine(username + "：断开链接");
            dic.Remove(client.GetIpPort());

            //广播给所有人，玩家退出游戏
            BroadAll(Protocol.PlayerLogOut, LitJson.JsonMapper.ToJson(client.userdata));
        }
    }

    //接收客户端消息，并进行分发
    public void OnMessage(SocketClient client, int protocol, string msg)
    {
        switch (protocol)
        {
            case Protocol.Login_CMD:

                bool hasplayer = false;
                User user = JsonMapper.ToObject<User>(msg);
                foreach (var item in dic)
                {
                    if (item.Value.userdata != null)//用户已经登录
                    {
                        if (item.Value.userdata.username == user.username)//用户名重复
                        {
                            hasplayer = true;
                        }
                    }
                }

                if (hasplayer)
                {
                    JsonData jd = new JsonData();
                    jd["error"] = "你的账户已经存在";
                    //还没有往字典存，client就是当前登录的玩家
                    client.SendMessage(Protocol.PlayerRepeatExit, JsonMapper.ToJson(jd));
                }
                else
                {
                    BroadOther(client, protocol, msg);
                    //登录后，才保存用户的信息
                    //把连接的用户存储起来
                    client.userdata = LitJson.JsonMapper.ToObject<User>(msg);
                    dic.Add(client.GetIpPort(), client);

                    dic[client.GetIpPort()].SendMessage(Protocol.SelfLogin_CMD, msg);
                }
                break;
            case Protocol.PlayerPosition_CMD:
                BroadOther(client, protocol, msg);
                break;
            case Protocol.PlayerMove_CMD:
                BroadOther(client, protocol, msg);
                break;
            case Protocol.PlayerFire_CMD:
                BroadOther(client, protocol, msg);
                break;
            case Protocol.PlayerOnHit_CMD:
                HitDat data = JsonMapper.ToObject<HitDat>(msg);
                string username = data.targetUsername;
                foreach (var item in dic)
                {
                    if (item.Value.userdata.username == username)
                    {
                        data.hp = --item.Value.userdata.hp;
                        if (data.hp<=0)
                        {
                            BroadAll(Protocol.PlayerDead_CMD, JsonMapper.ToJson(data));
                            break;
                        }
                        BroadAll(protocol, JsonMapper.ToJson(data));
                        break;
                    }
                }
                break;
            default:
                break;
        }
    }
}
